/*	--- 命令 --- 

#	将【一个请求】封装为【一个对象】，从而使你可以用【不同的请求】对【客户】进行【参数化】，对【请求排队】或【记录请求日志】，以及支持【可撤销的操作】。

=============================================================


【命令模式】（Command）是指，把【请求】封装成【一个命令】，然后【执行该命令】。

在【使用命令模式】前，我们先以【一个编辑器】为例子，看看如何实现【简单的编辑操作】： */
public class TextEditor {
	private StringBuilder buffer = new StringBuilder();

	public void add(String s) {
		buffer.append(s);
	}

	public void copy() {
		// ...
	}

	public void paste() {
		String text = getFromClipBoard();
		add(text);
	}

	public void delete() {
		if (buffer.length() > 0) {
			buffer.deleteCharAt(buffer.length() - 1);
		}
	}

	public String getState() {
		return buffer.toString();
	}
}


/*
我们用【一个StringBuilder】模拟【一个文本编辑器】，它支持【copy()、paste()、add()、delete()等方法】。

正常情况，我们像这样【调用TextEditor】： */
TextEditor editor = new TextEditor();
editor.add("Command pattern in text editor. \n");
editor.copy();
editor.paste();

System.out.println(editor.getState());


/*
这是直接调用【方法】，【调用方】需要了解【TextEditor的所有接口信息】。

----------------

如果改用【命令模式】，我们就要把【调用方 发送命令】和【执行方 执行命令】分开。

怎么分？

【解决方案】是引入【一个Command接口】： */
public interface Command {
	void execute();
}


/*
【调用方】创建一个【对应的Command】，然后【执行】，并【不关心内部】是如何具体执行的。

为了支持【CopyCommand】和【PasteCommand】这两个命令，我们从【Command接口】派生： */
public class CopyCommand implements Command {
	// 持有【执行者对象】
	private TextEditor receiver;

	public CopyCommand(TextEditor receiver) {
		this.receiver = receiver;
	}

	public void execute() {
		receiver.copy();
	}
}

public class PasteCommand implements Command {
	private TextEditor receiver;

	public PasteCommand(TextEditor receiver) {
		this.receiver = receiver;
	}

	public void execute() {
		receiver.paste();
	}
}


/*
最后我们把 Command 和 TextEditor 组装一下，【客户端】这么写： */
TextEditor editor = new TextEditor();
editor.add("Command pattern in text editor.\n");

// 执行一个【CopyCommand】
Command copy = new CopyCommand(editor);
copy.execute();

// 执行一个【PasteCommand】
Command paste = new PasteCommand(editor);
paste.execute();

System.out.println(editor.getState());


/*
这就是命令模式的结构：

	┌──────┐      ┌───────┐
	│Client│─ ─ ─>│Command│
	└──────┘      └───────┘
	                  │  ┌──────────────┐
	                  ├─>│ CopyCommand  │
	                  │  ├──────────────┤
	                  │  │editor.copy() │─ ┐
	                  │  └──────────────┘
	                  │                    │  ┌────────────┐
	                  │  ┌──────────────┐   ─>│ TextEditor │
	                  └─>│ PasteCommand │  │  └────────────┘
	                     ├──────────────┤
	                     │editor.paste()│─ ┘
	                     └──────────────┘

有的童鞋会有疑问：搞了一大堆Command，多了好几个类，还不如直接这么写简单： */
TextEditor editor = new TextEditor();
editor.add("Command pattern in text editor.\n");
editor.copy();
editor.paste();


/*
实际上，使用【命令模式】，确实增加了【系统的复杂度】。

如果需求很简单，那么【直接调用】显然更直观而且更简单。

--------------------------------

Q: 那么我们还需要【命令模式】吗？
A: 答案是【视需求而定】。

如果TextEditor【复杂到一定程度】，并且需要支持【Undo、Redo的功能】时，就需要使用【命令模式】，因为我们可以给【每个命令增加undo()】： */
public interface Command {
	void execute();
	void undo();
}


/*
然后把【执行的一系列命令】用【List】保存起来，就【既能支持Undo，又能支持Redo】。

这个时候，我们又需要一个【Invoker对象】，负责【执行命令】并【保存历史命令】：

┌─────────────┐
│   Client    │
└─────────────┘
       │

       │
       ▼
┌─────────────┐
│   Invoker   │
├─────────────┤    ┌───────┐
│List commands│─ ─>│Command│
│invoke(c)    │    └───────┘
│undo()       │        │  ┌──────────────┐
└─────────────┘        ├─>│ CopyCommand  │
                       │  ├──────────────┤
                       │  │editor.copy() │─ ┐
                       │  └──────────────┘
                       │                    │  ┌────────────┐
                       │  ┌──────────────┐   ─>│ TextEditor │
                       └─>│ PasteCommand │  │  └────────────┘
                          ├──────────────┤
                          │editor.paste()│─ ┘
                          └──────────────┘


可见，模式带来的设计复杂度的增加是随着需求而增加的，它减少的是系统各组件的耦合度。



==================================================================

#	练习

给命令模式新增Add和Delete命令并支持Undo、Redo操作。  */





/*===============================================================

#	----- 命令 の 小结 ----- 

1. 【命令模式的设计思想】是把【命令】的【创建和执行】分离，使得【调用者】无需关心【具体的执行过程】。

2. 通过封装【Command对象】，【命令模式】可以保存【已执行的命令】，从而支持【撤销、重做等操作】。


---------

简单总结:
	0. 创建一个接口【Interface Command】, 内部含有【
		核心功能 = execute();  
		辅助功能 = undo(), redo()等
	】 
		并以此接口,创建class

	1. 【命令模式】就是对【已有的Class和Class.Method】进行再一次封装,封装为【Command_Method】。
	
	2. 同时,需要创建【公有Command操作对象】, 例如: 
		TextEditor editor = new TextEditor();

	3. 每一次调用【Command_Method】,就载入【TextEditor editor】,并使用【Command_Method.execute()】调用Method

	4. 【每一个Command_Method】仅封装【一个核心Method + 多个辅助Method】, 例如: Method = Paste, 核心功能:Paste, 辅助功能(通用):撤回、取消、重做 等



*/










